﻿using Snake.GameBase;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static Snake.Snake;

namespace Snake
{
    class Scene
    {
        public Size Size { get; set; }
        public List<Point> FreePoints { get; set; }
        public Graphics Graphics { get; set; }
        public Snake Snake { get; set; }
        public FoodManager FoodManager { get; set; }
        public WallManager WallManager { get; set; }
        public GateManager GateManager { get; set; }
        public TrapManager TrapManager { get; set; }
        public static int Trunflag = 0;
        public int Score { get; set; }
        public float Speed { get; set; }

        public delegate void GameOveredHandler();
        public delegate void ScoreRefreshHandler(int score);
        public event GameOveredHandler GameOvered;
        public event ScoreRefreshHandler ScoreRefreshed;

        private SnakeDirection start_forbiden_direction;
        private int GenerateFoodFlag = 0;


        public Scene(int x, int y)
        {
            GameComponentFactory.DefaltSize = new Size(15, 15);
            FreePoints = new List<Point>();
            Size = new Size(x, y);
            for (int i = 1; i < Size.Width - 1; i++) 
            {
                for (int j = 1; j < Size.Height - 1; j++) 
                {
                    FreePoints.Add(new Point(i, j));
                }
            }
            start_forbiden_direction = SnakeDirection.Left;
        }

        private void GenerateFood()
        {
            Thread.Sleep(20);
            var r = new Random();
            var newfood = GameComponentFactory.CreateFood(FreePoints[r.Next(0, FreePoints.Count)]);
            FoodManager.Components.Add(newfood);
            newfood.Show(Graphics);
            GenerateFoodFlag = 0;
        }

        private void GenerateFood(int n)
        {
            if (n > 0)
                GenerateFood(n - 1);
            GenerateFood();
        }

        bool InitFlag = true;
        private List<IGameComponent> ConstantRefreshObj = new List<IGameComponent>();
        public void Refresh()
        {
            if (Snake.Graphics == null) Snake.Graphics = Graphics;
            if (InitFlag)
            {
                foreach(var snakebody in Snake.Components)
                {
                    foreach(var wall in WallManager.Components)
                    {
                        if (snakebody.Position == wall.Position)
                        {
                            ConstantRefreshObj.Add(wall);
                        }
                    }
                }
                Graphics.Clear(GameComponentFactory.ColorOfBackground);
                var allcomponens = new List<IGameComponent>();
                allcomponens.AddRange(FoodManager.Components);
                allcomponens.AddRange(Snake.Components);
                allcomponens.AddRange(WallManager.Components);
                allcomponens.AddRange(GateManager.Gates);
                allcomponens.AddRange(TrapManager.Traps);
                {
                    foreach (var component in allcomponens)
                    {
                        component.Show(Graphics);
                    }
                }
                Snake.Head.Show(Graphics);
                InitFlag = false;
                GC.Collect();
                return;
            }
            if (Snake.Direction != SnakeDirection.None)
            {
                Score -= Snake.Components.Count;
                if (Speed > 80) Speed -= 0.01f * Snake.Components.Count / 4;
            }
            var collisionobject = CollisionTest();
            if(collisionobject!=null)
            {
                if (collisionobject is Food)
                {
                    Snake.Refresh(Refreshflag.EatFood);
                    FoodManager.EatFood(collisionobject);
                    Score += (500 - (int)Speed) * Snake.Components.Count / 6;
                }
                if (collisionobject is Wall || collisionobject is SnakeComponent)
                {
                    throw new GameOverException();
                }
                if(collisionobject is Gate)
                {
                    Gate gate = (Gate)collisionobject;
                    Snake.Head.Position = gate.Arrival;
                    Snake.Direction = gate.Direction;
                    collisionobject.Show(Graphics);
                }
                if(collisionobject is Trap)
                {
                    //蛇的长度减一；并且分数减1000;如果蛇长等于初始值时撞到 trap ，游戏结束
                    if (Snake.Components.Count == 3)
                        throw new GameOverException();
                    else
                    {
                        Snake.Refresh(Refreshflag.TouchTrap);
                        TrapManager.TouchTrap(collisionobject);
                        Score -= (500 - (int)Speed) * Snake.Components.Count / 3;
                        if (Speed < 200) Speed += 0.01f * Snake.Components.Count;
                    }
                }
            }
            else
            {
                Snake.Refresh(Refreshflag.None);
                collisionobject = CollisionTest();
                if (collisionobject != null)
                {
                    if (collisionobject is Wall || collisionobject is SnakeComponent)
                    {
                        throw new GameOverException();
                    }
                }
            }

            if (FoodManager.Components.Count < FoodManager.MaxFoodNum)
            {
                GenerateFood(2);
                GenerateFoodFlag = 40;
            }
            foreach(var obj in ConstantRefreshObj)
            {
                obj.Show(Graphics);
            }
            Snake.Head.Show(Graphics);
            ScoreRefreshed?.Invoke(Score);
            GC.Collect();
        }

        public void ChangeDirection(SnakeDirection direction)
        {
            switch (Snake.Direction)
            {
                case SnakeDirection.Down:
                    if (direction == SnakeDirection.Up|| direction == SnakeDirection.Down) return;
                    break;
                case SnakeDirection.Up:
                    if (direction == SnakeDirection.Down|| direction == SnakeDirection.Up) return;
                    break;
                case SnakeDirection.Left:
                    if (direction == SnakeDirection.Right|| direction == SnakeDirection.Left) return;
                    break;
                case SnakeDirection.Right:
                    if (direction == SnakeDirection.Left|| direction == SnakeDirection.Right) return;
                    break;
                case SnakeDirection.None:
                    if (direction == start_forbiden_direction) return;
                    break;
            }
            
            Snake.Direction = direction;

        }

        protected Thread thread;
        private bool PauseFlag = false;

        public void Run()
        {
            thread = new Thread(delegate()
              {
                  bool alive = true;
                  while (alive)
                  {
                      while (PauseFlag) ;
                      try
                      {
                          Refresh();
                          Thread.Sleep((int)Speed-Trunflag-GenerateFoodFlag);
                          Trunflag = 0;
                          GenerateFoodFlag = 0;
                      }
                      catch (GameOverException)
                      {
                          alive = false;
                          GameOvered?.Invoke();
                      }
                  }
              });
            thread.Start();
        }

        public void EndThread()
        {
            thread.Abort();
        }

        public void Pause()
        {
            PauseFlag = true;
        }

        public void Continue()
        {
            PauseFlag = false;
        }

        private IGameComponent CollisionTest()//碰撞检测
        {
            IGameComponent SnakeHead = Snake.Head;
            foreach (var another in Snake.Components)
            {
                if (SnakeHead.Position == another.Position)
                {
                    return another;
                }
            }
            foreach (var another in FoodManager.Components)
            {
                if (SnakeHead.Position == another.Position)
                {
                    return another;
                }
            }
            foreach(var another in WallManager.Components)
            {
                if(SnakeHead.Position==another.Position)
                {
                    return another;
                }
            }
            foreach (var another in GateManager.Gates)
            {
                if (SnakeHead.Position == another.Position)
                {
                    return another;
                }
            }
            foreach (var another in TrapManager.Traps)
            {
                if (SnakeHead.Position == another.Position)
                {
                    return another;
                }
            }
            return null;
        }

        public Snake.SnakeDirection GetSnakeDirection()
        {
            return Snake.Direction;
        }

        public class GameOverException : Exception
        {
            public override string Message => "游戏结束";
        }

        public class NullSceneException:Exception
        {
            public override string Message => "场景未初始化";
        }
    }
}
